package one.stand.zuul.util;

import one.stand.advice.ResultEnum;
import one.stand.code.RedisCode;
import one.stand.util.AssertUtil;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Objects;
import java.util.concurrent.TimeUnit;


public class RateLimiter {
    private StringRedisTemplate redisTemplate;
    private Long rate;

    private RateLimiter() {
    }

    public static RateLimiter create(StringRedisTemplate redisTemplate, Long rate) {
        AssertUtil.nonNull(redisTemplate, ResultEnum.PARAM_CHECK);
        AssertUtil.nonNull(rate, ResultEnum.PARAM_CHECK);
        AssertUtil.isTrue(rate > 0, ResultEnum.PARAM_CHECK);

        RateLimiter rateLimiter = new RateLimiter();
        rateLimiter.redisTemplate = redisTemplate;
        rateLimiter.rate = rate;
        return rateLimiter;
    }

    public boolean tryRequire(String key) {
        String rateKey = RedisCode.requestLockCode(key);
        Long rateLimit = redisTemplate.opsForValue().increment(rateKey, 1);
        if (Objects.isNull(rateLimit)) return true;
        if (rateLimit == 1) {
            redisTemplate.expire(rateKey, 1, TimeUnit.SECONDS);
        }
        if (rateLimit <= rate) {
            return true;
        }

        redisTemplate.delete(rateKey);
        return false;
    }
}
